﻿
using System;
using System.Collections.Generic;

namespace GFramework
{
    /// <summary>
    /// 组合
    /// </summary>
    public abstract class Composite : Leaf
    {
        private Dictionary<Type, Leaf> _leafDict = new Dictionary<Type, Leaf>();

        virtual public Leaf Add(Leaf leaf)
        {
            Type type = leaf.GetType();
            if (this._leafDict.ContainsKey(type))
            {
                throw new GException($"Add, leaf already exist, id: {this.ID}, leaf: {type.Name}");
            }

            leaf.Parent = this;

            this._leafDict.Add(type, leaf);

            CompositeEventHelper.Start(leaf);

            return leaf;
        }

        virtual public TLeaf Add<TLeaf>() where TLeaf : Leaf, new()
        {
            TLeaf leaf = CompositeFactory.CreateWithParent<TLeaf>(this);
            Add(leaf);
            return leaf;
        }

        virtual public TLeaf Add<TLeaf, T>(T obj) where TLeaf : Leaf, new()
        {
            TLeaf leaf = CompositeFactory.CreateWithParent<TLeaf, T>(this, obj);
            Add(leaf);
            return leaf;
        }

        virtual public TLeaf Add<TLeaf, T1, T2>(T1 obj1, T2 obj2) where TLeaf : Leaf, new()
        {
            TLeaf leaf = CompositeFactory.CreateWithParent<TLeaf, T1, T2>(this, obj1, obj2);
            Add(leaf);
            return leaf;
        }

        virtual public TLeaf Add<TLeaf, T1, T2, T3>(T1 obj1, T2 obj2, T3 obj3) where TLeaf : Leaf, new()
        {
            TLeaf leaf = CompositeFactory.CreateWithParent<TLeaf, T1, T2, T3>(this, obj1, obj2, obj3);
            Add(leaf);
            return leaf;
        }

        virtual public TLeaf Get<TLeaf>() where TLeaf : Leaf, new()
        {
            Leaf leaf;
            if (!this._leafDict.TryGetValue(typeof(TLeaf), out leaf))
            {
                return default(TLeaf);
            }
            return (TLeaf)leaf;
        }

        virtual public void Remove<TLeaf>() where TLeaf : Leaf, new()
        {
            Type type = typeof(TLeaf);
            Leaf leaf;
            if (!this._leafDict.TryGetValue(type, out leaf))
            {
                return;
            }

            this._leafDict.Remove(type);

            leaf.Dispose();
        }

        override public void Clear()
        {
            foreach(Leaf leaf in _leafDict.Values)
            {
                leaf.Dispose();
            }
            this._leafDict.Clear();
        }
    }
}
